package com.base.core.utils;

import com.base.core.callback.MethodCallback;
import com.base.core.lang.ObjectUtils;
import com.base.core.lang.StringUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.cglib.beans.BeanMap;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * List工具类
 */
public class ListUtils extends org.apache.commons.collections.ListUtils {


    private static final Pattern linePattern = Pattern.compile("_(\\w)");

    /**
     * 是否包含字符串
     * @param str 验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
    public static boolean inString(String str, List<String> strs){
        if (str != null && strs != null){
            for (String s : strs){
                if (str.equals(StringUtils.trim(s))){
                    return true;
                }
            }
        }
        return false;
    }

    public static <E> ArrayList<E> newArrayList() {
        return new ArrayList<E>();
    }

    @SafeVarargs
    public static <E> ArrayList<E> newArrayList(E... elements) {
        ArrayList<E> list = new ArrayList<E>(elements.length);
        Collections.addAll(list, elements);
        return list;
    }

    public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
        return (elements instanceof Collection) ? new ArrayList<E>(cast(elements))
                : newArrayList(elements.iterator());
    }

    public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
        ArrayList<E> list = newArrayList();
        addAll(list, elements);
        return list;
    }

    public static <E> LinkedList<E> newLinkedList() {
        return new LinkedList<E>();
    }

    public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements) {
        LinkedList<E> list = newLinkedList();
        addAll(list, elements);
        return list;
    }

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList() {
        return new CopyOnWriteArrayList<E>();
    }

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(Iterable<? extends E> elements) {
        Collection<? extends E> elementsCollection = (elements instanceof Collection)
                ? cast(elements) : newArrayList(elements);
        return new CopyOnWriteArrayList<E>(elementsCollection);
    }

    private static <T> Collection<T> cast(Iterable<T> iterable) {
        return (Collection<T>) iterable;
    }

    private static <T> boolean addAll(Collection<T> addTo, Iterator<? extends T> iterator) {
        boolean wasModified = false;
        while (iterator.hasNext()) {
            wasModified |= addTo.add(iterator.next());
        }
        return wasModified;
    }

    public static <T> boolean addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd) {
        if (elementsToAdd instanceof Collection) {
            Collection<? extends T> c = cast(elementsToAdd);
            return addTo.addAll(c);
        }
        return addAll(addTo, elementsToAdd.iterator());
    }

    public static <T> List<Map<String,Object>> extractToListMap(List<T> list){
        List<Map<String,Object>> listMap= new ArrayList<>();
        try {
            for (T t : list) {
                Field[] fields=t.getClass().getDeclaredFields();
                Map<String, Object> m = new HashMap<String, Object>();
                for(Field field:fields){
                    String keyName=field.getName();
                    PropertyDescriptor pd = new PropertyDescriptor(keyName,t.getClass());
                    Method getMethod = pd.getReadMethod();// 获得getter方法
                    Object o = getMethod.invoke(t);// 执行get方法返回一个Object
                    m.put(keyName, o);
                }
                listMap.add(m);
            }
            return listMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * map转Bean
     * @param map
     * @param bean
     * @param <T>
     * @return
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        Map<String, Object> resMap = new HashMap<>();
        BeanMap beanMap = BeanMap.create(bean);
        map.forEach((k,v) ->{
            resMap.put(lineToHump(k),v);
        });
        beanMap.putAll(resMap);
        return bean;
    }

    public static <T> List<T> listMapsToBeans(List<Map<String, Object>> maps, Class<T> clazz){
        return CollectionUtils.isEmpty(maps) ? Collections.emptyList() :  maps.stream().map((v) -> {
            try {
                return mapToBean(v,clazz.getDeclaredConstructor().newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }).collect(Collectors.toList());
    }

    /**
     * 下划线转驼峰命名
     * @param str
     * @return
     */
    public static String lineToHump(String str) {
        str = str.toLowerCase();
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * 提取集合中的对象的两个属性(通过Getter函数), 组合成Map.
     * @param collection 来源集合.
     * @param keyPropertyName 要提取为Map中的Key值的属性名.
     * @param valuePropertyName 要提取为Map中的Value值的属性名.
     */
    public static Map extractToMap(final Collection collection, final String keyPropertyName,
                                   final String valuePropertyName) {
        Map map = new HashMap(collection.size());
        try {
            for (Object obj : collection) {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName),
                        PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectUtils.convertReflectionExceptionToUnchecked("", e);
        }
        return map;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     * @param collection 来源集合.
     * @param propertyName 要提取的属性名.
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> extractToList(final Collection collection, final String propertyName) {
        if (collection == null){
            return newArrayList();
        }
        List list = new ArrayList(collection.size());
        try {
            for (Object obj : collection) {
                list.add(PropertyUtils.getProperty(obj, propertyName));
            }
        } catch (Exception e) {
            throw ReflectUtils.convertReflectionExceptionToUnchecked("", e);
        }
        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     * @param collection 来源集合.
     * @param propertyName 要提取的属性名.
     * @param prefix 符合前缀的信息(为空则忽略前缀)
     * @param isNotBlank 仅包含不为空值(空字符串也排除)
     */
    public static List<String> extractToList(final Collection collection, final String propertyName,
                                             final String prefix, final boolean isNotBlank) {
        List<String> list = new ArrayList<String>(collection.size());
        try {
            for (Object obj : collection) {
                String value = (String)PropertyUtils.getProperty(obj, propertyName);
                if (StringUtils.isBlank(prefix) || StringUtils.startsWith(value, prefix)){
                    if (isNotBlank){
                        if (StringUtils.isNotBlank(value)){
                            list.add(value);
                        }
                    }else{
                        list.add(value);
                    }
                }
            }
        } catch (Exception e) {
            throw ReflectUtils.convertReflectionExceptionToUnchecked("", e);
        }
        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成由分割符分隔的字符串.
     *
     * @param collection 来源集合.
     * @param propertyName 要提取的属性名.
     * @param separator 分隔符.
     */
    public static String extractToString(final Collection collection, final String propertyName, final String separator) {
        List list = extractToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 中间以 separator分隔。
     */
    public static String convertToString(final Collection collection, final String separator) {
        return StringUtils.join(collection, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 每个元素的前面加入prefix，后面加入postfix，如<div>mymessage</div>。
     */
    public static String convertToString(final Collection collection, final String prefix, final String postfix) {
        StringBuilder builder = new StringBuilder();
        for (Object o : collection) {
            builder.append(prefix).append(o).append(postfix);
        }
        return builder.toString();
    }

    public static <K, V> Map<K, V> listToMap(List<V> list, String keyMethodName, Class<V> c) {
        Map<K, V> map = new HashMap<K, V>();
        if (list != null) {
            try {
                Method methodGetKey = c.getMethod(keyMethodName);
                for (int i = 0; i < list.size(); i++) {
                    V value = list.get(i);
                    //@SuppressWarnings("unchecked")
                    K key = (K) methodGetKey.invoke(list.get(i));
                    map.put(key, value);
                }
            } catch (Exception e) {
                throw new IllegalArgumentException("field can't match the key!");
            }
        }

        return map;
    }

    /**
     * 判断是否为空.
     */
    public static boolean isEmpty(Collection collection) {
        return (collection == null || collection.isEmpty());
    }

    /**
     * 判断是否为不为空.
     */
    public static boolean isNotEmpty(Collection collection) {
        return !(isEmpty(collection));
    }

    /**
     * 取得Collection的第一个元素，如果collection为空返回null.
     */
    public static <T> T getFirst(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        return collection.iterator().next();
    }

    /**
     * 获取Collection的最后一个元素 ，如果collection为空返回null.
     */
    public static <T> T getLast(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        //当类型为List时，直接取得最后一个元素 。
        if (collection instanceof List) {
            List<T> list = (List<T>) collection;
            return list.get(list.size() - 1);
        }
        //其他类型通过iterator滚动到最后一个元素.
        Iterator<T> iterator = collection.iterator();
        while (true) {
            T current = iterator.next();
            if (!iterator.hasNext()) {
                return current;
            }
        }
    }

    /**
     * 返回a+b的新List.
     */
    public static <T> List<T> union(final Collection<T> a, final Collection<T> b) {
        List<T> result = new ArrayList<T>(a);
        result.addAll(b);
        return result;
    }

    /**
     * 返回a-b的新List.
     */
    public static <T> List<T> subtract(final Collection<T> a, final Collection<T> b) {
        List<T> list = new ArrayList<T>(a);
        for (T element : b) {
            list.remove(element);
        }
        return list;
    }

    /**
     * 返回a与b的交集的新List.
     */
    public static <T> List<T> intersection(Collection<T> a, Collection<T> b) {
        List<T> list = new ArrayList<T>();
        for (T element : a) {
            if (b.contains(element)) {
                list.add(element);
            }
        }
        return list;
    }

	/**
	 * 将字符串使用“,”分隔，转换为，多对多中间表列表的转换
	 * @param clazz 当前实体类
	 * @param attrNameOne 中间表A字段
	 * @param attrValueOne 中间表A字段值
	 * @param attrNameTwo 中间表B字段名
	 * @param attrValueTwos 中间表B字段值（多个采用“,”分隔）
	 */
	public static <T> List<T> toManyToManyList(Class<T> clazz, String attrNameOne,
			String attrValueOne, String attrNameTwo, String attrValueTwos){
		List<T> list = ListUtils.newArrayList();
		if (attrValueTwos != null){
			for (String attrValueB : StringUtils.split(attrValueTwos, ",")){
				try {
					T t = clazz.newInstance();
					ReflectUtils.invokeSetter(t, attrNameOne, attrValueOne);
					ReflectUtils.invokeSetter(t, attrNameTwo, attrValueB);
					list.add(t);
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
		return list;
	}

    /**
     * 列表分页方法
     * @param list 数据源
     * @param pageSize 每页大小
     * @param pageCallback 分页回调，返回当前页的数据及分页信息（pageList, pageNo, pageSize）
     * @author ThinkGem
     */
    public static <T> void pageList(List<T> list, int pageSize, MethodCallback pageCallback){
        if (list != null && list.size() > 0){

            int count = list.size(), pageNo = 1;
            int totalPage = (count + pageSize - 1) / pageSize;

            while(true){

                // 执行回调，分页后的数据
                List<T> pageList = getPageList(list, pageNo, pageSize, totalPage);
                if (pageList.size() > 0){
                    pageCallback.execute(pageList, pageNo, pageSize, totalPage);
                }

                // 如果为最后一页，则跳出循环
                if (pageNo >= totalPage){
                    break;
                }

                // 页数加一继续下一页
                pageNo++;
            }
        }
    }

    /**
     * 列表分页方法
     * @param list 源数据
     * @param pageNo 当前页码
     * @param pageSize 每页显示条数
     * @param totalPage 总页码数
     * @author ThinkGem
     */
    public static <T> List<T> getPageList(List<T> list, int pageNo, int pageSize, int totalPage) {
        int fromIndex = 0; // 从哪里开始截取
        int toIndex = 0; // 截取几个
        if (list == null || list.size() == 0){
            return new ArrayList<T>();
        }
        // 当前页小于或等于总页数时执行
        if (pageNo <= totalPage && pageNo != 0) {
            fromIndex = (pageNo - 1) * pageSize;
            if (pageNo == totalPage) {
                toIndex = list.size();
            } else {
                toIndex = pageNo * pageSize;
            }
        }
        return list.subList(fromIndex, toIndex);
    }

    /**
     * 本地列表排序
     * @param list 需要排序的列表
     * @param orderBy 排序的键值（如：id desc）
     * @author ThinkGem
     */
    public static <T> List<T> listOrderBy(List<T> list, String orderBy){
        if (list != null && StringUtils.isNotBlank(orderBy)){
            final String[] ss = orderBy.trim().split(" ");
            if (ss != null){
                final String t = ss.length==2 ? ss[1] : "asc";
                Collections.sort(list, new Comparator<T>() {
                    @Override
                    public int compare(T o1, T o2) {
                        String s1 = StringUtils.EMPTY, s2 = StringUtils.EMPTY;
                        if (o1 instanceof Map){
                            s1 = ObjectUtils.toString(((Map)o1).get(ss[0]));
                            s2 = ObjectUtils.toString(((Map)o2).get(ss[0]));
                        }else{
                            s1 = ObjectUtils.toString(ReflectUtils.invokeGetter(o1, ss[0]));
                            s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0]));
                        }
                        if ("asc".equalsIgnoreCase(t)){
                            return s1.compareTo(s2);
                        }else{
                            return s2.compareTo(s1);
                        }
                    }
                });
            }
        }
        return list;
    }
}

